package com.young.context;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Map;
import java.util.TreeMap;

public final class InetTool {

    private static final String LOCAL_HOST_IP = "127.0.0.1";

    private static final String LOCAL_HOST_NAME = "localhost";

    //系统变量key
    public static final String HOST_NAME_SP_KEY = "HOST_NAME";

    //系统变量key
    public static final String LOCAL_IP_SP_KEY = "LOCAL_IP";

    public static final String HOST_NAME = hostName();

    //对于非docker环境，此值与HOST_NAME一样，对于docker环境，将会移除pod随机后缀
    public static final String HOST_NAME_FQN = hostName(true);

    public static final String LOCAL_IP = localIp();

    //是否为容器化部署环境：docker
    public static final boolean CONTAINERIZED = isContainerized();

    private static final String C_PART = "-pod-";


    static {
        System.setProperty(InetTool.HOST_NAME_SP_KEY, HOST_NAME);
        System.setProperty(InetTool.LOCAL_IP_SP_KEY, LOCAL_IP);
    }

    public static String getHostName() {
        return getHostName(false);
    }

    /**
     * @param fqn 是否为全名？对于docker容器，false时只获取hostname主要部分，不包含pod部分
     * @return
     */
    public static String getHostName(boolean fqn) {
        return fqn ? HOST_NAME_FQN : HOST_NAME;
    }

    public static String getLocalIp() {
        return LOCAL_IP;
    }

    /**
     * 获取本地网卡中，所有非回环地址，如果没找到则返回localhost
     *
     * @return
     */
    public static Collection<InetAddress> getAddresses() {
        //按照网卡，索引排序
        Map<Integer, InetAddress> result = new TreeMap<>();

        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface network = interfaces.nextElement();
                if (!network.isUp()) {
                    continue;
                }
                int index = network.getIndex();
                Enumeration<InetAddress> addresses = network.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress address = addresses.nextElement();
                    if (checkAddress(address)) {
                        //发现即覆盖
                        result.put(index, address);
                    }
                }
            }
        } catch (IOException e) {
            //
        }

        try {
            //如果没有合适的，则本地
            if (result.isEmpty()) {
                result.put(0, InetAddress.getLocalHost());
            }
        } catch (IOException e) {
            //
        }

        return result.values();
    }

    public static boolean isContainerized(String hostName) {
        return containerPartIndex(hostName) != -1;
    }

    /**
     * 检测获取的地址是否为本地IP，即127.0.0.1或者localhost
     *
     * @return
     */
    public static boolean isLocal() {
        return LOCAL_IP.equals(LOCAL_HOST_IP) || HOST_NAME.equals(LOCAL_HOST_NAME);
    }

    /**
     * 获取hostName或者IP，优先获得本机的内网IPV4地址，如果无法获取，返回"127.0.0.1";
     * 重新解析hostName
     *
     * @return
     */
    private static String localIp() {
        return hostAddress().getHostAddress();
    }

    private static String hostName() {
        return hostName(false);
    }

    private static String hostName(boolean fqn) {
        //修正，hostName需要与ip地址保持对应解析关系
        try {
            String hostName = InetAddress.getLocalHost().getHostName();
            if (fqn) {
                return hostName;
            }
            int i = containerPartIndex(hostName);
            if (i == -1) {
                return hostName;
            }
            return hostName.substring(0, i);
        } catch (IOException e) {
            return LOCAL_HOST_NAME;
        }
    }

    /**
     * 检测hostName中是否包含容器的特殊标志字符串
     *
     * @param hostName
     * @return
     */
    protected static int containerPartIndex(String hostName) {
        int i = hostName.lastIndexOf(".");
        //如果不存在，或者是最后一个
        if (i == -1 || i == hostName.length() - 1) {
            return -1;
        }
        String suffix = hostName.substring(i);
        return suffix.contains(C_PART) ? i : -1;
    }

    /**
     * 是否为容器内部署
     *
     * @return
     */
    public static boolean isContainerized() {
        return isContainerized(HOST_NAME_FQN);
    }

    /**
     * 保持一致性
     *
     * @return
     */
    private static InetAddress hostAddress() {
        return getAddresses().iterator().next();
    }


    /**
     * 检测地址是否为非回环地址，且为IPV4
     *
     * @param address
     * @return
     */
    private static boolean checkAddress(InetAddress address) {
        //只获取172.，192.，10.域IP
        if (!address.isLoopbackAddress()
                && address.isSiteLocalAddress()
                && (address instanceof Inet4Address)) {
            return true;
        }

        return false;
    }

}
